home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / ARGONET / PD / PROGRAMMING / DESKLIBC / SOURCES.ZIP / DeskLib / !DLSources / Libraries / Menu / c / NewMenu < prev    next >
Text File  |  1995-07-08  |  7KB  |  247 lines

  1. /*
  2.     ####             #    #     # #
  3.     #   #            #    #       #          The FreeWare C library for
  4.     #   #  ##   ###  #  # #     # ###             RISC OS machines
  5.     #   # #  # #     # #  #     # #  #   ___________________________________
  6.     #   # ####  ###  ##   #     # #  #
  7.     #   # #        # # #  #     # #  #    Please refer to the accompanying
  8.     ####   ### ####  #  # ##### # ###    documentation for conditions of use
  9.     ________________________________________________________________________
  10.  
  11.     File:    Menu.NewMenu.c
  12.     Author:  Copyright © 1993 Shaun Blackmore and Jason Williams,
  13.                        © 1994 Tony Houghton
  14.                        © 1995 Neil Tarrant
  15.     Version: 1.05 (16 May 1995)
  16.     Purpose: Creates a new menu given a textual description string
  17.     Mods:    24 Sep 1994  -  TH  -  Can now cope with indirected menu titles in
  18.                                     >= RISC OS 3.1
  19.              16 May 1995  - Neil Tarrant - malloc(1+titlelen).
  20. */
  21.  
  22.  
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. #include "DeskLib:Core.h"
  27. #include "DeskLib:Error.h"
  28. #include "DeskLib:Event.h"
  29. #include "DeskLib:Screen.h"
  30. #include "DeskLib:Wimp.h"
  31. #include "DeskLib:Menu.h"
  32.  
  33. #include "MenuDefs.h"
  34.  
  35.  
  36. /* Description format:
  37.  *      opt   :- " "  no special options (i.e. leading spaces are skipped)
  38.  *               "!"  ticked
  39.  *               "~"  shaded
  40.  *               ">"  has submenu/subwindow
  41.  *               "-"  dotted
  42.  *      name  :- any character except "," and "|"
  43.  *      entry :- {opt}* name
  44.  *      sep   :- ","  to separate normal items
  45.  *               "|"  to separate items and place a dotted line between them
  46.  *      descr :- entry {sep entry}*
  47.  *
  48.  *      EXAMPLE:
  49.  *        ">Info, Create, Quit"
  50.  *        "!Ticked,~Disabled|>Submenu"
  51.  */
  52.  
  53.  
  54. extern void Menu__CountItems(char *description, int *numitems, int *menuwidth)
  55. /*  For internal use - counts the number of items in a menu description
  56.  *  string, and also returns the widest menu item (in terms of characters)
  57.  */
  58. {
  59.   char *s;
  60.   int  width = 0, maxwidth = 0, count = 0;
  61.   BOOL in_option = TRUE;
  62.  
  63.   for (s = description; *s; s++)
  64.   {
  65.     if (*s == ',' || *s == '|')
  66.     {
  67.      if (width > maxwidth)
  68.        maxwidth = width;
  69.      count++;
  70.      width = 0;
  71.      in_option = TRUE;
  72.     }
  73.     else
  74.     {
  75.       if (in_option)
  76.       {
  77.         if(*s != '!' && *s != '>' && *s != '~' && *s != ' ')
  78.         {
  79.           in_option = FALSE;
  80.           width++;
  81.         }
  82.       }
  83.       else
  84.         width++;
  85.     }
  86.   }
  87.  
  88.   *numitems = count + 1;                    /* Count last item and its width */
  89.  
  90.   if (width > maxwidth)
  91.     maxwidth=width;
  92.  
  93.   *menuwidth = maxwidth + 1;       /* Add room for a gap/sublink arrows, etc */
  94. }
  95.  
  96.  
  97. extern BOOL Menu__Create(menu_item *item, char *description, int numitems)
  98. {
  99.   menu_item *it;
  100.   char *s, *t;
  101.   int  i, index;
  102.   BOOL foundtext;
  103.  
  104.   s = description;
  105.   for (i = 0; i < numitems; i++)
  106.   {
  107.     it = &item[i];
  108.     it->menuflags.value = 0;
  109.     it->submenu.value   = NULL;
  110.     it->iconflags.value = icon_TEXT | icon_FILLED;
  111.     it->iconflags.data.foreground = 7;
  112.  
  113.     foundtext = FALSE;
  114.     do
  115.     {
  116.       switch(*s++)
  117.       {
  118.         case '!':
  119.           it->menuflags.data.ticked = TRUE;
  120.           break;
  121.  
  122.         case '~':
  123.           it->iconflags.data.shaded = TRUE;
  124.           break;
  125.  
  126.         case '>':
  127.           it->menuflags.data.notifysub = TRUE;  /* Ask for sublink warnings */
  128.           it->submenu.value = 1;                /* This is sublink item '1' */
  129.           break;
  130.  
  131.         case ' ':  /* No option */
  132.           break;
  133.  
  134.         default:   /* Any other == start of menu item text, so don't lose it */
  135.           s--;
  136.           foundtext = TRUE;
  137.           break;
  138.       }
  139.     } while (!foundtext);
  140.  
  141.     t = s;
  142.     for (index = 0; ; index++)
  143.       if (t[index] == 0 || t[index] == '|' || t[index] == ',')
  144.         break;
  145.  
  146.     if (index <= wimp_MAXNAME)
  147.       t = it->icondata.text;            /* Copy text directly into menu item */
  148.     else
  149.     {
  150.       /* Copy text into indirected menu item */
  151.       it->iconflags.data.indirected = TRUE;
  152.       it->icondata.indirecttext.buffer = malloc(index + 1);
  153.       if (it->icondata.indirecttext.buffer == NULL)
  154.         return(Error_OutOfMemory(FALSE, "menus"));
  155.  
  156.       it->icondata.indirecttext.bufflen = index + 1;
  157.       it->icondata.indirecttext.validstring = (char *) -1;
  158.  
  159.       t = it->icondata.indirecttext.buffer;
  160.     }
  161.  
  162.     while (*s != 0 && *s != ',' && *s != '|')
  163.       *t++ = *s++;
  164.  
  165.     if (index != wimp_MAXNAME)     /* Only terminate if not exactly 12 chars */
  166.       *t = 0;
  167.  
  168.     if (*s++ == '|')                        /* Step over separator...        */
  169.       it->menuflags.data.dotted = TRUE;     /* ...setting 'dotted' if needed */
  170.   }
  171.  
  172.   return(TRUE);
  173. }
  174.  
  175.  
  176.  
  177. extern menu_ptr Menu_New(char *title, char *description)
  178. {
  179.   menu_ptr   menu;
  180.   menu_item  *item;
  181.   int        numitems, maxwidth;
  182.   int        titlelen;
  183.   int        trunclen;
  184.  
  185.   /*  Copy the string. If it's less than 12 characters we need it to be
  186.    *  zero-terminated. We can let it go to 12 chars without any terminator
  187.    *  though, so we don't need to bother terminating after the strncpy.
  188.    */
  189.  
  190.   Menu__CountItems(description, &numitems, &maxwidth);
  191.  
  192.   titlelen = strlen(title);
  193.  
  194.   /* Make sure menu is wide enough for truncated title  */
  195.   trunclen = titlelen > wimp_MAXNAME ? wimp_MAXNAME : titlelen;
  196.   if (trunclen > maxwidth)
  197.     maxwidth = trunclen;
  198.  
  199.   menu = (menu_ptr) malloc(sizeof(menu_block) + (numitems * sizeof(menu_item)));
  200.  
  201.   if (menu == NULL)
  202.     return((menu_ptr) Error_OutOfMemory(FALSE, "menus"));
  203.  
  204.   item = (menu_item *) &(menu[1]);
  205.  
  206.   strncpy(menu->title, title, wimp_MAXNAME);
  207.  
  208.   menu->titlefore = 7;
  209.   menu->titleback = 2;
  210.   menu->workfore  = 7;
  211.   menu->workback  = 0;
  212.   menu->width     = maxwidth * 16;
  213.   menu->height    = 44;
  214.   menu->gap       = 0;
  215.  
  216.   if (!Menu__Create(item, description, numitems))
  217.     return((menu_ptr) NULL);
  218.   item[numitems - 1].menuflags.data.last = TRUE;
  219.  
  220.   /* If title > 12 chars and we've got RISC OS 3 make it indirected */
  221.   if (titlelen > wimp_MAXNAME && event_wimpversion >= 310)
  222.   {
  223.     char *titledata;
  224.     icon_data *titleicon;
  225.     menu_item *firstitem;
  226.  
  227.     /* Set up data as for indirected text icon */
  228.     if (titledata = malloc(1+titlelen), !titledata)    /* +1 courtesy of Neil Tarrant */
  229.       return (menu);
  230.     strcpy(titledata,title);
  231.     titleicon = (icon_data *) &menu->title;
  232.     titleicon->indirecttext.buffer = titledata;
  233.     titleicon->indirecttext.validstring = (char *) -1;
  234.     titleicon->indirecttext.bufflen = titlelen;
  235.  
  236.     /* Set flag in first item to inicate indirected title */
  237.     firstitem = (menu_item *) ((int) menu + sizeof(menu_block));
  238.     firstitem->menuflags.data.indtitle = 1;
  239.  
  240.     /* Make sure it is wide enough for indirected title  */
  241.     if (titlelen > maxwidth)
  242.       maxwidth = strlen(title);
  243.   }
  244.   return(menu);
  245. }
  246.  
  247.